﻿#include "server.h"
#include <iostream>
#include <string.h>
#include <event.h>
#include <event2/listener.h>  
#include <event2/bufferevent.h>  
#include <thread>
#include <netinet/in.h>  
#include <sys/socket.h>  
#include <arpa/inet.h>

using namespace std;

ChatDataBase* Server::chatdb = new ChatDataBase;
Utils* Server::utils = new Utils;

struct bufferevent* Server::bev_list[kMaxConnectionNum] = { nullptr };
char clientIp[INET_ADDRSTRLEN];
int linkNumber;

Server::Server(const char* ip, int port) {
	chatList = new ChatIist;//创建一个链表对象

	// 创建事件集合
	base = event_base_new();
	if (base == nullptr) {  // 如果事件集合创建失败，输出错误信息
		cout << "event_base_new error" << endl;
	}
	cout << "创建事件集合成功" << endl;

	struct sockaddr_in serverAddr;
	memset(&serverAddr, 0, sizeof(serverAddr));

	// 设置服务器地址
	serverAddr.sin_family = AF_INET;// 设置地址族为 IPv4
	serverAddr.sin_port = htons(port);// 设置端口号，转换为网络字节序（大小端）
	inet_pton(AF_INET, ip, &serverAddr.sin_addr);// 将IP地址转换为网络字节序，并保存到地址结构体中

	// 创建监听对象
	listener = evconnlistener_new_bind(base, listenerCallback, this,
		BEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
		kMaxConnectionNum, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
	if (nullptr == listener) {  // 如果监听对象创建失败，输出错误信息
		cout << "evconnlistener_new_bind error" << endl;
	}
	cout << "监听对象创建成功" << endl;

	cout << "服务器初始化成功 开始监听客户端" << endl;
}

Server::~Server() {
	for (int i = 0; i < linkNumber; i++) {  // 释放所有缓冲区事件对象
		if (bev_list[i] != nullptr) {
			bufferevent_free(bev_list[i]);
		}
	}
	if (listener != nullptr) {// 释放监听对象
		evconnlistener_free(listener);
	}
	if (base != nullptr) {// 释放事件集合对象
		event_base_free(base);
	}
}

// 启动服务器
void Server::startServer() {
	if (base != nullptr) { // 如果事件集合对象存在，则开始运行事件循环
		event_base_dispatch(base);
	}
}

// 停止服务器
void Server::stopServer() {
	if (base != nullptr) {  // 如果事件集合对象存在，则停止事件循环
		event_base_loopbreak(base);
	}
}

// 监听回调函数，当有客户端连接到服务器时会被调用
void Server::listenerCallback(evconnlistener* listener, evutil_socket_t fd,
	sockaddr* addr, int socklen, void* arg) {
	Server* server = (Server*)arg;

	cout << "接受客户端的连接，fd = " << fd << endl;
	linkNumber++;

	getClientIp(addr);

	// 创建工作线程来处理该客户端
	for (int i = 0; i < kMaxConnectionNum; i++) {
		thread clientThread(&Server::clientHandler, server, fd); // C++11 新特性，创建线程
		clientThread.detach();// 线程分离，当线程运行结束后，自动释放资源
	}

	// 将新连接的缓冲区事件对象加入到列表中
	server->bev_list[linkNumber - 1] = bufferevent_socket_new(server->base, fd, BEV_OPT_CLOSE_ON_FREE);
}

// 客户端处理函数，在工作线程中运行，负责接收客户端发来的消息，并进行相应的处理
void Server::clientHandler(int fd) {
	// 创建事件集合
	struct event_base* base = event_base_new();

	// 创建bufferevent对象
	struct bufferevent* bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
	if (bev == nullptr) {
		cout << "bufferevent_socket_new error" << endl;
	}

	// 给bufferevent设置回调函数
	bufferevent_setcb(bev, readCallback, NULL, eventCallback, NULL);


	// 使能回调函数
	// 在这里，使用了 EV_READ | EV_WRITE，因为 bufferevent 同时能支持读写事件
	bufferevent_enable(bev, EV_READ | EV_WRITE);

	// 运行事件循环
	int ret = event_base_dispatch(base);
	if (ret < 0) { // 错误处理
		cout << "event_base_dispatch error" << endl;
	}

	// 释放事件集合对象
	event_base_free(base);
}

// 读回调函数，在客户端发送消息时被调用
void Server::readCallback(bufferevent* bev, void* ctx) {
	struct evbuffer* input_buf = bufferevent_get_input(bev);  // 获取输入缓冲区
	char buf[4096];
	size_t len = evbuffer_get_length(input_buf);
	if (len > 0) {
		evbuffer_remove(input_buf, buf, len);
		buf[len] = '\0';
		printf("receive data from client: %s\n", buf);

		char result[INET_ADDRSTRLEN + 2 + sizeof(buf)] = { 0 };
		strcpy(result, clientIp);
		strcat(result, ":");
		strcat(result, buf);


		for (int i = 0; i < linkNumber; i++) {
			struct evbuffer* output_buf = bufferevent_get_output(bev_list[i]);  // 获取输出缓冲区
			if (evbuffer_add(output_buf, result, strlen(result)) != 0) {  // 将数据添加到输出缓冲区
				printf("send data failed\n");
			}

			int ret = bufferevent_flush(bev_list[i], EV_WRITE, BEV_FLUSH);  // 刷新输出缓冲区，确保数据已经写入
			if (ret != 0) {
				printf("send data failed\n");
			}
		}


	}


#if 0
	Json::Value val;
	Json::Reader reader;		// 解析json对象
	Json::FastWriter writer;	// 封装json对象

	if (!reader.parse(msg, msg + len, val)) {// 把字符串解析成 json 对象
		cout << "服务器解析数据失败" << endl;
		Json::Value err_val;
		err_val["errmsg"] = "parse error";
		err_val["errcode"] = -1;
		bufferevent_write(bev, writer.write(err_val).c_str(), strlen(writer.write(err_val).c_str())); // 返回错误提示信息
	}
	string cmd = val["cmd"].asString();
	if (cmd == "register") {// 注册功能
		registerUser(bev, val);
	}
	else {
		// 对收到的消息进行相应的处理
		bufferevent_write(bev, msg, len); // 将消息内容原样返回给客户端
	}
#endif
}

void Server::writeCallback(bufferevent* bev, const void* data, size_t size) {

}

void Server::eventCallback(bufferevent* bev, short what, void* ctx) {
	if (what & BEV_EVENT_EOF) {  // 如果客户端通过 shutdown 关闭了连接
		cout << "Connection closed." << endl;
	}
	else if (what & BEV_EVENT_ERROR) {  // 如果发生错误
		cout << "Error occurred." << endl;
	}
	// 释放资源
	bufferevent_free(bev);
}

// 用户注册函数的实现
void Server::registerUser(bufferevent* bev, const Json::Value& val) {
	// 连接用户数据库
	chatdb->connectToDataBase("user");

	if (chatdb->isUserExist(val["user"].asString())) {// 如果用户已经存在
		Json::Value reply;
		reply["cmd"] = "register_reply";
		reply["result"] = "failure";

		// 将消息转为字符串并发送给客户端
		string s = Json::FastWriter().write(reply);
		if (bufferevent_write(bev, s.c_str(), strlen(s.c_str())) < 0) {
			cout << "bufferevent_write error" << endl;
		}
	}
	else {// 如果用户不存在
		// 在数据库中创建新用户并设置密码
		chatdb->userPassword(val["user"].asString(), val["password"].asString());

		// 设置注册成功消息返回给客户端
		Json::Value reply;
		reply["cmd"] = "register_reply";
		reply["result"] = "success";

		// 将消息转为字符串并发送给客户端
		string message = Json::FastWriter().write(reply);
		if (bufferevent_write(bev, message.c_str(), strlen(message.c_str())) < 0) {
			cout << "bufferevent_write error" << endl;
		}
	}
	// 断开用户数据库连接
	chatdb->disconnectToDataBase();
}

void Server::getClientIp(struct sockaddr* addr) {
	struct sockaddr_in* client_addr = (struct sockaddr_in*)addr;
	int client_port = ntohs(client_addr->sin_port);
	inet_ntop(AF_INET, &client_addr->sin_addr, clientIp, INET_ADDRSTRLEN);
	//printf("New connection from %s:%d\n", clientIp, client_port);
}
